package com.situ.mall.service.impl;

import com.situ.mall.mapper.ProductMapper;
import com.situ.mall.pojo.Product;
import com.situ.mall.service.IProductService;
import com.situ.mall.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Service
public class ProductServiceImpl implements IProductService {
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<Product> selectByCategoryId(Integer id) {
        return productMapper.selectByCategoryId(id);
    }

    @Override
    public Product selectById(Integer id) {
        return productMapper.selectByPrimaryKey(id);
    }

    @Override
    public Result secondKill(Integer productId, Integer userId) {
        //userId随机生成，代表不同用户参与productId这个商品的秒杀  [0,5000)
        userId = new Random().nextInt(5000);
        System.out.println("userId:" + userId);

        //库存key  sk:27:qt   sk:29:qt
        String quantityKey = "sk:" + productId + ":qt";
        //秒杀成功用户的key，set集合
        String userKey = "sk:" + productId + ":user";

        List<String> keyList = new ArrayList<>();
        keyList.add(quantityKey);
        keyList.add(userKey);
        //调用lua脚本
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Long.class);
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/second_kill.lua")));
        Long result = (Long) redisTemplate.execute(redisScript, keyList, userId);
        //--[[返回1表示秒杀成功,2表示秒杀结束,3表示已经参加过秒杀]]
        if (result == 3) {
            System.out.println("已经秒杀成功，不能重复参与秒杀");
            return Result.error("已经秒杀成功，不能重复参与秒杀");
        } else if (result == 2) {
            System.out.println("秒杀已经结束");
            return Result.error("秒杀已经结束");
        } else {
            System.out.println("秒杀成功");
            return Result.ok("秒杀成功");
        }

    }

    //@Override
    public Result secondKill3(Integer productId, Integer userId) {
        //userId随机生成，代表不同用户参与productId这个商品的秒杀  [0,5000)
        userId = new Random().nextInt(5000);
        System.out.println("userId:" + userId);

        //库存key  sk:27:qt   sk:29:qt
        String quantityKey = "sk:" + productId + ":qt";
        //秒杀成功用户的key，set集合
        String userKey = "sk:" + productId + ":user";


        Integer finalUserId = userId;
        Object result = redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                operations.watch(quantityKey);

                //获取库存，如果库存为null，代表秒杀还没有开始
                Integer quantity = (Integer) redisTemplate.opsForValue().get(quantityKey);
                if (quantity == null) {
                    System.out.println("秒杀还没有开始，请等候");
                    return Result.error("秒杀还没有开始，请等候");
                }

                //判断用户是不是重复参与了秒杀
                if (redisTemplate.opsForSet().isMember(userKey, finalUserId)) {
                    System.out.println("已经秒杀成功，不能重复参与秒杀");
                    return Result.error("已经秒杀成功，不能重复参与秒杀");
                }

                //判断商品数量，库存<=0代表秒杀已经结束
                if (quantity <= 0) {
                    System.out.println("秒杀已经结束");
                    return Result.error("秒杀已经结束");
                }

                //秒杀过程
                //使用事物
                operations.multi();
                redisTemplate.opsForValue().decrement(quantityKey, 1);
                redisTemplate.opsForSet().add(userKey, finalUserId);
                List list = operations.exec();
                System.out.println(list);
                if (CollectionUtils.isEmpty(list)) {
                    return Result.error("秒杀失败");
                } else {
                    return Result.ok("秒杀成功");
                }

            }
        });

        return (Result) result;
    }

    //@Override
    public synchronized Result secondKill2(Integer productId, Integer userId) {
        //userId随机生成，代表不同用户参与productId这个商品的秒杀  [0,5000)
        userId = new Random().nextInt(5000);
        System.out.println("userId:" + userId);

        //库存key  sk:27:qt   sk:29:qt
        String quantityKey = "sk:" + productId + ":qt";
        //秒杀成功用户的key，set集合
        String userKey = "sk:" + productId + ":user";

        //获取库存，如果库存为null，代表秒杀还没有开始
        Integer quantity = (Integer) redisTemplate.opsForValue().get(quantityKey);
        if (quantity == null) {
            System.out.println("秒杀还没有开始，请等候");
            return Result.error("秒杀还没有开始，请等候");
        }

        //判断用户是不是重复参与了秒杀
        if (redisTemplate.opsForSet().isMember(userKey, userId)) {
            System.out.println("已经秒杀成功，不能重复参与秒杀");
            return Result.error("已经秒杀成功，不能重复参与秒杀");
        }

        //判断商品数量，库存<=0代表秒杀已经结束
        if (quantity <= 0) {
            System.out.println("秒杀已经结束");
            return Result.error("秒杀已经结束");
        }

        //秒杀过程
        //不使用事物
        redisTemplate.opsForValue().decrement(quantityKey, 1);
        redisTemplate.opsForSet().add(userKey, userId);


        return Result.ok("秒杀成功");
    }

    //@Override
    public Result secondKill1(Integer productId, Integer userId) {
        //userId随机生成，代表不同用户参与productId这个商品的秒杀  [0,5000)
        userId = new Random().nextInt(5000);
        System.out.println("userId:" + userId);

        //库存key  sk:27:qt   sk:29:qt
        String quantityKey = "sk:" + productId + ":qt";
        //秒杀成功用户的key，set集合
        String userKey = "sk:" + productId + ":user";

        //获取库存，如果库存为null，代表秒杀还没有开始
        Integer quantity = (Integer) redisTemplate.opsForValue().get(quantityKey);
        if (quantity == null) {
            System.out.println("秒杀还没有开始，请等候");
            return Result.error("秒杀还没有开始，请等候");
        }

        //判断用户是不是重复参与了秒杀
        if (redisTemplate.opsForSet().isMember(userKey, userId)) {
            System.out.println("已经秒杀成功，不能重复参与秒杀");
            return Result.error("已经秒杀成功，不能重复参与秒杀");
        }

        //判断商品数量，库存<=0代表秒杀已经结束
        if (quantity <= 0) {
            System.out.println("秒杀已经结束");
            return Result.error("秒杀已经结束");
        }

        //秒杀过程
        //不使用事物
        redisTemplate.opsForValue().decrement(quantityKey, 1);
        redisTemplate.opsForSet().add(userKey, userId);


        return Result.ok("秒杀成功");
    }
}
